"use strict";
import H from "./../../parts/Globals.js";
import U from "./../../parts/Utilities.js";
var extend = U.extend;

import controllableMixin from "./controllableMixin.js";
import markerMixin from "./markerMixin.js";

// See TRACKER_FILL in highcharts.src.js
var TRACKER_FILL = "rgba(192,192,192," + (H.svg ? 0.0001 : 0.002) + ")";

/**
 * A controllable path class.
 *
 * @class
 * @mixes Annotation.controllableMixin
 * @mixes Annotation.markerMixin
 * @memberOf Annotation
 *
 * @param {Highcharts.Annotation}
 * @param {Object} options a path's options object
 * @param {number} index of the path
 **/
function ControllablePath(annotation, options, index) {
  this.init(annotation, options, index);
  this.collection = "shapes";
}

/**
 * @typedef {Object} Annotation.ControllablePath.AttrsMap
 * @property {string} dashStyle=dashstyle
 * @property {string} strokeWidth=stroke-width
 * @property {string} stroke=stroke
 * @property {string} fill=fill
 * @property {string} zIndex=zIndex
 */

/**
 * A map object which allows to map options attributes to element attributes
 *
 * @type {Annotation.ControllablePath.AttrsMap}
 */
ControllablePath.attrsMap = {
  dashStyle: "dashstyle",
  strokeWidth: "stroke-width",
  stroke: "stroke",
  fill: "fill",
  zIndex: "zIndex",
};

H.merge(
  true,
  ControllablePath.prototype,
  controllableMixin,
  /** @lends Annotation.ControllablePath# */ {
    /**
     * @type 'path'
     */
    type: "path",

    setMarkers: markerMixin.setItemMarkers,

    /**
     * Map the controllable path to 'd' path attribute
     *
     * @return {Array<(string|number)>} a path's d attribute
     */
    toD: function () {
      var d = this.options.d;

      if (d) {
        return typeof d === "function" ? d.call(this) : d;
      }

      var points = this.points,
        len = points.length,
        showPath = len,
        point = points[0],
        position = showPath && this.anchor(point).absolutePosition,
        pointIndex = 0,
        dIndex = 2,
        command;

      d = position && ["M", position.x, position.y];

      while (++pointIndex < len && showPath) {
        point = points[pointIndex];
        command = point.command || "L";
        position = this.anchor(point).absolutePosition;

        if (command === "Z") {
          d[++dIndex] = command;
        } else {
          if (command !== points[pointIndex - 1].command) {
            d[++dIndex] = command;
          }

          d[++dIndex] = position.x;
          d[++dIndex] = position.y;
        }

        showPath = point.series.visible;
      }

      return showPath
        ? this.chart.renderer.crispLine(d, this.graphic.strokeWidth())
        : null;
    },

    shouldBeDrawn: function () {
      return (
        controllableMixin.shouldBeDrawn.call(this) || Boolean(this.options.d)
      );
    },

    render: function (parent) {
      var options = this.options,
        attrs = this.attrsFromOptions(options);

      this.graphic = this.annotation.chart.renderer
        .path(["M", 0, 0])
        .attr(attrs)
        .add(parent);

      if (options.className) {
        this.graphic.addClass(options.className);
      }

      this.tracker = this.annotation.chart.renderer
        .path(["M", 0, 0])
        .addClass("highcharts-tracker-line")
        .attr({
          zIndex: 2,
        })
        .add(parent);

      if (!this.annotation.chart.styledMode) {
        this.tracker.attr({
          "stroke-linejoin": "round", // #1225
          stroke: TRACKER_FILL,
          fill: TRACKER_FILL,
          "stroke-width": this.graphic.strokeWidth() + options.snap * 2,
        });
      }

      controllableMixin.render.call(this);

      extend(this.graphic, {
        markerStartSetter: markerMixin.markerStartSetter,
        markerEndSetter: markerMixin.markerEndSetter,
      });

      this.setMarkers(this);
    },

    redraw: function (animation) {
      var d = this.toD(),
        action = animation ? "animate" : "attr";

      if (d) {
        this.graphic[action]({ d: d });
        this.tracker[action]({ d: d });
      } else {
        this.graphic.attr({ d: "M 0 " + -9e9 });
        this.tracker.attr({ d: "M 0 " + -9e9 });
      }

      this.graphic.placed = this.tracker.placed = Boolean(d);

      controllableMixin.redraw.call(this, animation);
    },
  }
);

export default ControllablePath;
